package com.ruoyi.qd.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.func.LambdaUtil;
import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryMethods;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.ruoyi.common.core.page.PageDomain;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.qd.domain.Order;
import com.ruoyi.qd.domain.Robot;
import com.ruoyi.qd.domain.RobotQueue;
import com.ruoyi.qd.enums.OrderStatusEnum;
import com.ruoyi.qd.enums.RobotQueueStatusEnum;
import com.ruoyi.qd.enums.TradeWaterTypeEnum;
import com.ruoyi.qd.mapper.RobotQueueMapper;
import com.ruoyi.qd.service.IRobotQueueService;
import com.ruoyi.qd.vo.RobotQueueNow;
import com.ruoyi.qd.vo.RobotQueueNowRes;
import com.ruoyi.qd.vo.RobotQueuePageReq;
import com.ruoyi.qd.vo.RobotQueuePageRes;
import com.ruoyi.qd.vo.TradeWaterAddReq;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Objects;

import static com.ruoyi.common.core.domain.entity.table.SysUserTableDef.SYS_USER;
import static com.ruoyi.qd.domain.table.OrderTableDef.ORDER;
import static com.ruoyi.qd.domain.table.RobotQueueTableDef.ROBOT_QUEUE;
import static com.ruoyi.qd.domain.table.RobotTableDef.ROBOT;

/**
 * 机器人队列Service业务层处理
 *
 * @author tushiguang
 * @date 2024-07-25
 */
@Service
public class RobotQueueServiceImpl extends ServiceImpl<RobotQueueMapper, RobotQueue> implements IRobotQueueService {
    @Autowired
    private TradeWaterServiceImpl tradeWaterService;

    @Override
    public RobotQueueNowRes listRobotQueueNow(String robotSn) {
        List<RobotQueueNow> robotQueueNowList = Robot.create()
                .select(
                        ROBOT.ID.as(LambdaUtil.getFieldName(RobotQueueNow::getRobotId)),
                        ROBOT.TITLE.as(LambdaUtil.getFieldName(RobotQueueNow::getRobotTitle)),
                        ROBOT.SN.as(LambdaUtil.getFieldName(RobotQueueNow::getRobotSn)),
                        ROBOT.IMAGE.as(LambdaUtil.getFieldName(RobotQueueNow::getRobotImage)),
                        ROBOT_QUEUE.ID.as(LambdaUtil.getFieldName(RobotQueueNow::getQueueId)),
                        ROBOT_QUEUE.APPOINTMENT_TIME.as(LambdaUtil.getFieldName(RobotQueueNow::getAppointmentTime)),
                        ROBOT_QUEUE.STATUS.as(LambdaUtil.getFieldName(RobotQueueNow::getStatus)),
                        ORDER.ID.as(LambdaUtil.getFieldName(RobotQueueNow::getOrderId)),
                        ORDER.ORDER_NO.as(LambdaUtil.getFieldName(RobotQueueNow::getOrderNo)),
                        SYS_USER.USER_ID.as(LambdaUtil.getFieldName(RobotQueueNow::getUserId)),
                        SYS_USER.USER_NAME.as(LambdaUtil.getFieldName(RobotQueueNow::getUserName)),
                        SYS_USER.NICK_NAME.as(LambdaUtil.getFieldName(RobotQueueNow::getNickName))
                )
                .leftJoin(ROBOT_QUEUE).on(ROBOT_QUEUE.ROBOT_ID.eq(ROBOT.ID)
                        .and(ROBOT_QUEUE.STATUS.in(RobotQueueStatusEnum.LINE.getCode(),
                                RobotQueueStatusEnum.CALL.getCode(),
                                RobotQueueStatusEnum.PROCESS.getCode()))
                        .and(QueryMethods.dateFormat(RobotQueue::getAppointmentTime, "%Y-%m-%d")
                                .eq(DateUtil.today())))
                .leftJoin(ORDER).on(ORDER.ID.eq(ROBOT_QUEUE.ORDER_ID))
                .leftJoin(SYS_USER).on(SYS_USER.USER_ID.eq(ROBOT_QUEUE.USER_ID))
                .where(ROBOT.SN.eq(robotSn))
                .orderBy(ROBOT_QUEUE.APPOINTMENT_TIME.asc())
                .listAs(RobotQueueNow.class);

        RobotQueueNowRes robotQueueNowRes = new RobotQueueNowRes();
        if (CollectionUtil.isEmpty(robotQueueNowList)) {
            return robotQueueNowRes;
        }

        RobotQueueNow robotQueueNowT = robotQueueNowList.get(0);
        robotQueueNowRes.setRobotId(robotQueueNowT.getRobotId());
        robotQueueNowRes.setRobotTitle(robotQueueNowT.getRobotTitle());
        robotQueueNowRes.setRobotSn(robotQueueNowT.getRobotSn());
        robotQueueNowRes.setRobotImage(robotQueueNowT.getRobotImage());

        for (RobotQueueNow robotQueueNow : robotQueueNowList) {
            Long queueId = robotQueueNow.getQueueId();
            if (Objects.isNull(queueId)) {
                break;
            }

            RobotQueueNowRes.Base base = new RobotQueueNowRes.Base();
            base.setQueueId(queueId);
            base.setUserId(robotQueueNow.getUserId());
            base.setUserName(robotQueueNow.getUserName());
            base.setNickName(robotQueueNow.getNickName());
            base.setOrderId(robotQueueNow.getOrderId());
            base.setOrderNo(robotQueueNow.getOrderNo());
            base.setAppointmentTime(robotQueueNow.getAppointmentTime());
            base.setStatus(robotQueueNow.getStatus());
            base.setStatusStr(RobotQueueStatusEnum.getInfoByCode(robotQueueNow.getStatus()));

            RobotQueueStatusEnum robotQueueStatusEnum = RobotQueueStatusEnum.getByCode(robotQueueNow.getStatus());
            switch (Objects.requireNonNull(robotQueueStatusEnum)) {
                case LINE:
                    robotQueueNowRes.getLines().add(base);
                    break;
                case CALL:
                    robotQueueNowRes.setCall(base);
                    robotQueueNowRes.getAlls().add(base);
                    break;
                case PROCESS:
                    robotQueueNowRes.setProcess(base);
                    robotQueueNowRes.getAlls().add(base);
                    break;
                default:
                    break;
            }
        }
        robotQueueNowRes.getAlls().addAll(robotQueueNowRes.getLines());

        return robotQueueNowRes;
    }

    /**
     * 批量删除机器人队列
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteRobotQueueByIds(Long[] ids) {
        for (Long id : ids) {
            // 修改订单状态为用户取消
            RobotQueue robotQueue = mapper.selectOneById(id);
            Order.create()
                    .setStatus(OrderStatusEnum.SYSTEM_CANCEL.getCode())
                    .setUpdateBy(SecurityUtils.getUsername())
                    .where(Order::getId).eq(robotQueue.getOrderId())
                    .update();

            // 退款
            Order order = Order.create().where(Order::getId).eq(robotQueue.getOrderId()).one();
            TradeWaterAddReq tradeWaterAddReq = new TradeWaterAddReq();
            tradeWaterAddReq.setAmount(order.getMoney());
            tradeWaterAddReq.setType(TradeWaterTypeEnum.SYSTEM_CANCEL_APPOINTMENT_ROBOT_REFUND.getCode());
            tradeWaterAddReq.setUserId(order.getUserId());
            tradeWaterService.add(tradeWaterAddReq);

            // 删除队列
            mapper.deleteById(id);
        }
    }

    @Override
    public List<String> listRobotAppointmentByRobotId(Long robotId) {
        List<Date> dates = RobotQueue.create()
                .select(RobotQueue::getAppointmentTime)
                .where(RobotQueue::getRobotId).eq(robotId)
                .and(RobotQueue::getStatus).in(RobotQueueStatusEnum.LINE.getCode(),
                        RobotQueueStatusEnum.CALL.getCode(),
                        RobotQueueStatusEnum.PROCESS.getCode(),
                        RobotQueueStatusEnum.COMPLETED.getCode())
                .listAs(Date.class);

        List<String> result = Lists.newArrayList();
        for (Date date : dates) {
            result.add(DateUtil.formatDateTime(date));
        }
        return result;
    }

    /**
     * 查询机器人队列
     *
     * @param id 机器人队列主键
     * @return 机器人队列
     */
    @Override
    public RobotQueue selectRobotQueueById(Long id) {
        return mapper.selectOneById(id);
    }

    @Override
    public Page<RobotQueuePageRes> selectRobotQueuePage(PageDomain pageDomain, RobotQueuePageReq robotQueuePageReq) {
        RobotQueue robotQueue = RobotQueue.create()
                .select(ROBOT_QUEUE.ALL_COLUMNS,
                        SYS_USER.USER_NAME,
                        ORDER.ORDER_NO,
                        ROBOT.TITLE.as(LambdaUtil.getFieldName(RobotQueuePageRes::getRobotTitle)),
                        ROBOT.SN.as(LambdaUtil.getFieldName(RobotQueuePageRes::getRobotSn)))
                .leftJoin(ROBOT).on(ROBOT.ID.eq(ROBOT_QUEUE.ROBOT_ID))
                .leftJoin(SYS_USER).on(SYS_USER.USER_ID.eq(ROBOT_QUEUE.USER_ID))
                .leftJoin(ORDER).on(ORDER.ID.eq(ROBOT_QUEUE.ORDER_ID))
                .where(QueryMethods.date(ROBOT_QUEUE.APPOINTMENT_TIME).eq(robotQueuePageReq.getAppointmentTime()))
                .and(ROBOT.TITLE.like(robotQueuePageReq.getRobotTitle()))
                .and(ROBOT.SN.eq(robotQueuePageReq.getRobotSn()))
                .and(SYS_USER.USER_NAME.like(robotQueuePageReq.getUserName()))
                .orderBy(ROBOT_QUEUE.ID.desc());
//        String status = robotQueuePageReq.getStatus();
//        if (StrUtil.isNotBlank(status)) {
//            robotQueue.and(ROBOT_QUEUE.STATUS.eq(status));
//        } else {
//            robotQueue.and(ROBOT_QUEUE.STATUS.notIn(RobotQueueStatusEnum.COMPLETED.getCode(),
//                    RobotQueueStatusEnum.EXPIRED.getCode()));
//        }
        return robotQueue.pageAs(new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize()),
                RobotQueuePageRes.class);
    }

    /**
     * 查询机器人队列列表
     *
     * @param robotQueue 机器人队列
     * @return 机器人队列
     */
    @Override
    public List<RobotQueue> selectRobotQueueList(RobotQueue robotQueue) {
        QueryWrapper query = buildWrapper(robotQueue);
        return mapper.selectListByQuery(query);
    }

    public QueryWrapper buildWrapper(RobotQueue robotQueue) {
        return query()
                .where(ROBOT_QUEUE.ROBOT_ID.eq(robotQueue.getRobotId()))
                .and(ROBOT_QUEUE.USER_ID.eq(robotQueue.getUserId()))
                .and(ROBOT_QUEUE.APPOINTMENT_TIME.eq(robotQueue.getAppointmentTime()))
                .and(ROBOT_QUEUE.STATUS.eq(robotQueue.getStatus()));
    }

    /**
     * 新增机器人队列
     *
     * @param robotQueue 机器人队列
     * @return 结果
     */
    @Override
    public int insertRobotQueue(RobotQueue robotQueue) {
        return mapper.insertSelective(robotQueue);
    }

    /**
     * 修改机器人队列
     *
     * @param robotQueue 机器人队列
     * @return 结果
     */
    @Override
    public int updateRobotQueue(RobotQueue robotQueue) {
        return mapper.update(robotQueue);
    }

    /**
     * 删除机器人队列信息
     *
     * @param id 机器人队列主键
     * @return 结果
     */
    @Override
    public int deleteRobotQueueById(Long id) {
        return mapper.deleteById(id);
    }
}
